package com.incar.chuxing.utils.ble.bean;

import com.incar.chuxing.utils.ble.utils.ConvertHelper;
import com.incar.chuxing.utils.ble.utils.DateTimeHelper;

import java.util.ArrayList;
import java.util.List;

public class ZisGpsBean extends ZisBaseBean {
    //    public int GTID;
    public long CreatedTime;
    public long GpsTime;
    public double Longitude;
    public double Latitude;
    public int Altitude;//高度
    public int Speed;
    public int Direction;
    public int SalState;
    //卫星数量
    public int SalCount;
    ////绑定状态	BYTE	0x01：不定位
    //0x02：2D绑定
    //0x03：3D绑定
    public int BindState;

    public ZisGpsBean() {
        CreatedTime = System.currentTimeMillis();
    }

    public static long getGpsTime(byte[] bytes, int start) {
        try {
            int n = start;
            int b = bytes[n] & 0xff;
            if (b < 14 || b > 24)
                return -1;

            return DateTimeHelper.getTimeOfUTC((bytes[n] & 0xff) + 2000, bytes[n + 1] & 0xff, bytes[n + 2] & 0xff, bytes[n + 3] & 0xff, bytes[n + 4] & 0xff, bytes[n + 5] & 0xff);
        } catch (Exception e) {
            return -1;
        }
    }

    public static long getGpsTime3(byte[] bytes, int start) {
        try {
            int n = start;

            if ((bytes[n] & 0xff) == 0 && (bytes[n + 1] & 0xff) == 0 && (bytes[n + 2] & 0xff) == 0 && (bytes[n + 3] & 0xff) == 0)
                return -1;

            return ConvertHelper.bytesToInt(bytes[n], bytes[n + 1], bytes[n + 2], bytes[n + 3]) * 1000;
        } catch (Exception e) {
            return -1;
        }
    }

    public static boolean isValidGps2(byte[] bytes, int start) {
        return !((bytes[start + 6] & 0xff) == 0 && (bytes[start + 7] & 0xff) == 0 && (bytes[start + 8] & 0xff) == 0 && (bytes[start + 9] & 0xff) == 0);
    }

    public static boolean isValidGps3(byte[] bytes, int start) {
        return (bytes[start + 17] & 0xff) > 1;
    }

    public static ZisGpsBean createBean2(int gtid, String idc, long receivedTime, byte[] bytes, int start) {
        try {
            int n = start;
            ZisGpsBean bean = new ZisGpsBean();
//            bean.GTID = gtid;
            bean.IDC = idc;
            bean.ReceivedTime = receivedTime;

            bean.GpsTime = DateTimeHelper.getTimeOfUTC((bytes[n] & 0xff) + 2000, bytes[n + 1] & 0xff, bytes[n + 2] & 0xff, bytes[n + 3] & 0xff, bytes[n + 4] & 0xff, bytes[n + 5] & 0xff);

            n += 6;

            bean.Longitude = ConverTude2Double(bytes, n);
            n += 4;
            bean.Latitude = ConverTude2Double(bytes, n);
            n += 4;

            bean.Speed = (int) ((bytes[n++] & 0xff) * 1.852);
            bean.Direction = bytes[n++] & 0xff;
            bean.Altitude = Math.min(30000, ConvertHelper.bytesToInt(bytes[n], bytes[n + 1]));
            n += 2;

            bean.BindState = -1;
            bean.SalState = bytes[n++] & 0xff;
            bean.SalCount = bytes[n++] & 0xff;

            return bean;
        } catch (Exception ex) {
//            SmsSender.getInstance().send(String.format("ZisGpsBean:CreateBean:%s", ex.getMessage()), false);
//            log.error("ZisGpsBean:CreateBean", ex);
        }

        return null;
    }


    /**
     * 解析gps
     *
     * @param idc
     * @param receivedTime
     * @param bytes
     * @param start
     * @return
     */
//    public static ZisGpsBean CreateBean3(String idc, long receivedTime, byte[] bytes, int start) {
//        try {
//            int n = start;
//            ZisGpsBean bean = new ZisGpsBean();
//            bean.IDC = idc;
//            bean.ReceivedTime = DateTimeHelper.ConvertToDateByTick(receivedTime);
//
//            bean.GpsTime = DateTimeHelper.ConvertToDateBySecond(ConvertHelper.bytesToInt(bytes[n], bytes[n + 1], bytes[n + 2], bytes[n + 3]));
//
//            n += 4;
//
//            bean.Longitude = ZisGpsBean.ConverTude2Double(bytes, n);
//            n += 4;
//            bean.Latitude = ZisGpsBean.ConverTude2Double(bytes, n);
//            n += 4;
//
//            bean.Speed = ConvertHelper.bytesToInt(bytes[n], bytes[n + 1]) / 10;
//            n += 2;
//
//            bean.Direction = bytes[n++];
//            bean.Altitude = Math.min(30000, ConvertHelper.bytesToInt(bytes[n], bytes[n + 1]));
//            n += 2;
//
//            bean.SalState = -1;
//            bean.BindState = bytes[n++];
//            bean.SalCount = bytes[n++];
//
//            return bean;
//        } catch (Exception ex) {
////            Infrastructure.SmsSender.getInstance().SendByConfigPhones(string.Format("ZisGpsBean:CreateBean:{0}", ex.Message), false);
////            CallLogger.LogException(typeof(ZisGpsBean), ex, idc);
//        }
//
//        return null;
//    }

    /**
     * 解析gps
     *
     * @param idc
     * @param receivedTime
     * @param bytes
     * @param start
     * @return 7e10 001a 01cb 0283 01 595f334e740f03082734452800030000143100305b
     * 0091 0283 01 595f5bc7740f043c2734490a00000000400308
     */
    public static ZisGpsBean createBean3(String idc, long receivedTime, byte[] bytes, int start) {
        try {
            int n = start;
            ZisGpsBean bean = new ZisGpsBean();
//            bean.GTID = gtid;
            bean.IDC = idc;
            bean.ReceivedTime = receivedTime;

            bean.GpsTime = ConvertHelper.bytesToInt(bytes[n], bytes[n + 1], bytes[n + 2], bytes[n + 3]) * 1000L;

            n += 4;

            bean.Longitude = ConverTude2Double(bytes, n);
            n += 4;
            bean.Latitude = ConverTude2Double(bytes, n);
            n += 4;

            bean.Speed = ConvertHelper.bytesToInt(bytes[n], bytes[n + 1]) / 10;
            n += 2;

            bean.Direction = bytes[n++] & 0xff;
            bean.Altitude = Math.min(30000, ConvertHelper.bytesToInt(bytes[n], bytes[n + 1]));
            n += 2;

            bean.SalState = -1;
            bean.BindState = bytes[n++] & 0xff;
            bean.SalCount = bytes[n++] & 0xff;

            return bean;
        } catch (Exception ex) {
//            SmsSender.getInstance().send(String.format("ZisGpsBean:CreateBean3:%s", ex.getMessage()), false);
//            log.error("ZisGpsBean:CreateBean3", ex);
            ex.printStackTrace();
        }

        return null;
    }

//    public static List<ZisGpsBean> createBeans(MapMessage map) throws Exception {
//        int gtid = map.getInt("GTID");
//        String idc = map.getString("IDC");
//        long receivedTime = map.getLong("RECEIVETIME");
//        byte[] bytes = map.getBytes("PROTOCOLDATA");
//        int pVer = map.itemExists("VERSION") ? map.getInt("VERSION") : 2;
//        //byte[] bytes = ConvertHelper.HexStringToByteArray("010E030A022D36740F56002735042900000045240D");
//
//        try {
//            List<ZisGpsBean> list = new ArrayList<ZisGpsBean>();
//            if (bytes[0] > 0)//the new gps packet
//            {
//                int n = 1;
//                int len = bytes[0] & 0xff;
//                for (int i = 0; i < len; i++) {
//                    ZisGpsBean bean = null;
//                    if (pVer == 2) {
//                        bean = createBean2(gtid, idc, receivedTime, bytes, n);
//                        n += 20;
//                    } else if (pVer == 3) {
//                        bean = createBean3(gtid, idc, receivedTime, bytes, n);
//                        n += 19;
//                    }
//                    if (bean != null)
//                        list.add(bean);
//
//                }
//            } else {
//                int n = 4;
//                ZisGpsBean bean = new ZisGpsBean();
//                list.add(bean);
//
//                bean.IDC = idc;
//                bean.ReceivedTime = receivedTime;
//
//                bean.GpsTime = DateTimeHelper.getTimeOfUTC((bytes[n] & 0xff) + 2000, bytes[n + 1] & 0xff, bytes[n + 2] & 0xff, bytes[n + 3] & 0xff, bytes[n + 4] & 0xff, bytes[n + 5] & 0xff);
//
//                n += 6;
//
//                bean.Longitude = ConverTude2Double(bytes, n);
//                n += 4;
//                bean.Latitude = ConverTude2Double(bytes, n);
//                n += 4;
//                bean.Speed = (int) ((bytes[n++] & 0xff) * 1.852);
//                bean.Direction = bytes[n++] & 0xff;
//
//                n += 3;
//
//                bean.Altitude = Math.min(30000, ConvertHelper.bytesToInt(bytes[n], bytes[n + 1]));
//                n += 2;
//                bean.SalState = bytes[n++] & 0xff;
//                bean.SalCount = bytes[n++] & 0xff;
//
//            }
//
//            return list;
//        } catch (Exception ex) {
//            throw new Exception("ZisGpsBean data ERROR." + ex.getMessage());
//        }
//
//    }

    public static double ConverTude2Double(byte[] bytes, int start) {
        double londu = bytes[start] & 0xff;
        double lonfen1 = bytes[start + 1] & 0xff;
        double lonfen2 = (double) (bytes[start + 2] & 0xff) / (double) 100;
        double lonfen3 = (double) (bytes[start + 3] & 0xff) / (double) 10000;
        double lond = (lonfen1 + lonfen2 + lonfen3) / (double) 60;
        return londu + lond;
    }

    private static List<ZisGpsBean> speedFilter(List<ZisGpsBean> sps) {
        List<ZisGpsBean> rps = new ArrayList<ZisGpsBean>();
        int maxSpeed = 3;
        int maxLoop = 3;
        boolean isFilter = false;
        int i = 0;
        while (i < sps.size()) {
            if (!isFilter) {
                rps.add(sps.get(i));

                boolean isExist = true;
                for (int j = 0; j < maxLoop; j++) {
                    if (i + j >= sps.size() || sps.get(i + j).Speed > maxSpeed) {
                        isExist = false;
                        break;
                    }
                }
                if (isExist) {
                    isFilter = true;
                    i += maxLoop;
                    continue;
                }
            } else {
                boolean isExist = true;
                for (int j = 0; j < maxLoop; j++) {
                    if (i + j >= sps.size() || sps.get(i + j).Speed <= maxSpeed) {
                        isExist = false;
                        break;
                    }
                }
                if (isExist) {
                    isFilter = false;
                    rps.add(sps.get(i));
                }

            }
            i++;
        }

        return rps;
    }

    private static List<ZisGpsBean> distanceFilter(List<ZisGpsBean> ds) {
        int arrayCount = 5;
        List<ZisGpsBean> rps = new ArrayList<ZisGpsBean>();
        int count = ds.size();
        int aftern;
        List<ZisGpsBean> temps = new ArrayList<ZisGpsBean>();
        for (int i = 0; i < count; i++) {
            aftern = count - i - 1;
            if (aftern < arrayCount && i > aftern) {
                temps.clear();
                for (int j = i - 1; j >= 0; j--) {
                    if (temps.size() == arrayCount)
                        break;
                    temps.add(ds.get(j));
                }
                if (isValidDistanceInArray(arrayCount, ds.get(i), temps, 0))
                    rps.add(ds.get(i));

            } else {
                if (isValidDistanceInArray(arrayCount, ds.get(i), ds, i + 1))
                    rps.add(ds.get(i));
            }
        }
        return rps;
    }

    private static boolean isValidDistanceInArray(int ArrayCount, ZisGpsBean d, List<ZisGpsBean> ds, int start) {
        int m, n, j;
        int count = ds.size();
        boolean isValid;
        m = n = 0;
        isValid = true;
        int sn = ArrayCount / 2 + 1;
        for (j = 0; j < ArrayCount; j++) {
            if (start + j >= count) {
                if (m == 0 && n > 0)
                    isValid = false;
                break;
            }
            if (d.GpsTime == ds.get(start + j).GpsTime) {
                isValid = false;
                break;
            }
            if (isValidDistance(d, ds.get(start + j)))
                m++;
            else
                n++;

            if (m == sn && n == 0)
                break;
            if (n == sn && m == 0) {
                isValid = false;
                break;
            }
        }
        if (j == ArrayCount && n > m)
            isValid = false;

        return isValid;
    }

    private static boolean isValidDistance(ZisGpsBean d1, ZisGpsBean d2) {
        double sec = Math.abs(d1.GpsTime - d2.GpsTime) / 1000;

        double d = distance((double) d1.Longitude, (double) d1.Latitude, (double) d2.Longitude, (double) d2.Latitude);
        if (d > 60 * Math.abs(sec))// 6 * 30 * 65)
            return false;

        boolean ret = (d / sec) < 65;
        if (!ret) {
            int i = 1;
            i++;
        }
        return ret;
    }

    public static double distance(double long1, double lat1, double long2, double lat2) {
        double a, b, R;
        R = 6378137; //地球半径
        lat1 = lat1 * Math.PI / 180.0;
        lat2 = lat2 * Math.PI / 180.0;
        a = lat1 - lat2;
        b = (long1 - long2) * Math.PI / 180.0;
        double d;
        double sa2, sb2;
        sa2 = Math.sin(a / 2.0);
        sb2 = Math.sin(b / 2.0);
        d = 2 * R * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));
        return d;
    }

    public static int calcGpsMilage(List<ZisGpsBean> ds) {
        List<ZisGpsBean> ds1 = distanceFilter(speedFilter(ds));

        double mil;
        double tempMil = 0;
        int n = ds1.size();
        for (int i = 0; i < n - 1; i++) {
            mil = distance((double) ds1.get(i).Longitude, (double) ds1.get(i).Latitude, (double) ds1.get(i + 1).Longitude, (double) ds1.get(i + 1).Latitude);

            tempMil += mil;
        }
        return (int) (tempMil + 0.5);
    }

//    public String toString() {
//        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        String timeStr = fmt.format(new Date(GpsTime));
//
//        return String.format("GTID=%d,IDC=%s,GpsTime=%s",
//                GTID, IDC, timeStr);
//
//    }


    @Override
    public String toString() {
        return "ZisGpsBean{" +
                "\nCreatedTime=" + CreatedTime +
                ", \nGpsTime=" + GpsTime +
                ", \nLongitude=" + Longitude +
                ", \nLatitude=" + Latitude +
                ", \nAltitude(高度)=" + Altitude +
                ", \nSpeed=" + Speed +
                ", \nDirection(方向)=" + Direction +
                ", \nSalState=" + SalState +
                ", \nSalCount(卫星数量)=" + SalCount +
                ", \nBindState(绑定状态)=" + BindState +
                '}';
    }

    /**
     * @param bytes
     * @return -1代表解析出错 1代表不定位，其他值代表定位
     */
    public static int parseBindState(byte[] bytes) {
        try {
            int n = 26;
            if (bytes.length >= 26) {
                return bytes[n] & 0xff;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return -1;
    }

}
